#pragma once
#include <string>
#include <iostream>
#include <jsoncpp/json/json.h>
#include <memory>
#include <sstream>

// 计算器的协议
namespace wxd
{
    const std::string sep = "\r\n";

    // 添加报头的方法
    //{json} -> len\r\n{json}\r\n
    bool Encode(std::string &message)
    {
        message = std::to_string(message.size()) + sep + message + sep;
        return true;
    }

    // 去除报头的方法
    // len\r\n{json}\r\n
    bool Decode(std::string &package, std::string &content)
    {
        // 验证报头完整性
        int pos = package.find(sep);
        // 报头不完整，返回继续读
        if (pos == std::string::npos)
            return false;
        // 报头完整,取报头,判断报文完整性
        std::string lenstr = package.substr(0, pos);
        size_t len;
        //std::cout<<"lenstr = "<<lenstr<<std::endl;

        try
        {
            len = std::stoi(lenstr);
        }
        catch (const std::exception &e)
        {
            std::cerr << e.what() << '\n';
            exit(1);
        }

        size_t full_len = lenstr.size() + 2 * sep.size() + len;
        // 报文不完整继续读
        if (package.size() < full_len)
            return false;

        // 确认完整报文->提取内容，去除处理过的完整报文
        content = package.substr(pos + sep.size(), pos + sep.size() + len);
        package.erase(0, full_len);
        return true;
    }

    class Request
    {
    public:
        Request()
            : _x(0), _y(0), _oper(0)
        {
        }
        Request(int x, int y, char oper)
            : _x(x), _y(y), _oper(oper)
        {
        }
        // 序列化 将序列化结果带出来
        bool Serialize(std::string &message)
        {
            Json::Value root;
            root["_x"] = _x;
            root["_y"] = _y;
            root["_oper"] = _oper;

            Json::StreamWriterBuilder wbuilder;
            std::unique_ptr<Json::StreamWriter> writer_ptr(wbuilder.newStreamWriter());
            // 将序列化结果写入字符串
            std::stringstream ss;
            writer_ptr->write(root, &ss);
            message = ss.str();
            return true;
            // std::cout<<message<<std::endl;  //debug
        }

        // 反序列化
        // request的  {json} -> 结构化
        bool Deserialize(const std::string message)
        {
            Json::Reader reader;
            Json::Value root;

            reader.parse(message, root);
            _x = root["_x"].asInt();
            _y = root["_y"].asInt();
            _oper = root["_oper"].asInt();

            return true;
        }

        void PrintDebug()
        {
            std::cout << "_x = " << _x << std::endl;
            std::cout << "_y = " << _y << std::endl;
            std::cout << "_oper = " << _oper << std::endl;
        }

        int X() const
        {
            return _x;
        }
        int Y() const
        {
            return _y;
        }
        char Oper() const
        {
            return _oper;
        }

    private:
        int _x;
        int _y;
        char _oper;
    };

    class Response
    {
    public:
        Response()
            : _result(0), _cal_code(0)
        {
        }

        // 序列化 将序列化结果带出来
        bool Serialize(std::string &message)
        {
            Json::Value root;
            root["_result"] = _result;
            root["_cal_code"] = _cal_code;

            Json::StreamWriterBuilder wbuilder;
            std::unique_ptr<Json::StreamWriter> writer_ptr(wbuilder.newStreamWriter());
            // 将序列化结果写入字符串
            std::stringstream ss;
            writer_ptr->write(root, &ss);
            message = ss.str();

            return true;
        }

        // 反序列化
        // response的  {json} -> 结构化
        bool Deserialize(const std::string message)
        {
            Json::Reader reader;
            Json::Value root;

            reader.parse(message, root);
            _result = root["_result"].asInt();
            _cal_code = root["_cal_code"].asInt();

            return true;
        }

        void SetResult(int ret)
        {
            _result = ret;
        }
        void SetCalCode(int code)
        {
            _cal_code = code;
        }
        int Result() const
        {
            return _result;
        }
        int CalCode() const
        {
            return _cal_code;
        }

    private:
        int _result;
        int _cal_code;
    };
    
    
}